package withLamportClock;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;

/**
 * aqui fica as funcoes utilizadas pelos dois algoritmos!
 * a saber:
 * sendSemop
 * receiveSemop
 * broadcastSemop
 * sendGo
 * receiveGo
 *  
 * @author jjeske
 *
 */
public class NetFunctions {
	
	private static final int REQV = 21;
	private static final int REQP = 22;
	private static final int VOP  = 23;
	private static final int POP  = 24;
	private static final int ACK  = 25;
	
	static Logger logger = Logger.getLogger(NetFunctions.class);
	
	private static final Level level = Level.FATAL; //ajustar para ERROR para ver os erros de sockets !
	
	
	
	/**
	 * manda uma mensagem para processo em portaDestinatario,
	 * a mensagem contem: portaLocal, msg, lc
	 * @param portaDestinatario
	 * @param portaLocal
	 * @param msg
	 * @param timeStamp
	 */
	public static boolean sendSemop(int portaDestinatario, Message message){
		logger.setLevel(level);
		try {
			Socket sendSocket = new Socket("localhost",portaDestinatario);
			DataOutputStream out = new DataOutputStream(sendSocket.getOutputStream());
			out.writeInt(message.getPorta());
			out.writeInt(message.getMsg());
			out.writeInt(message.getTimeStamp());
			out.close();
			sendSocket.close();
		} catch (UnknownHostException e) {			
			logger.error(e.getMessage());// e.printStackTrace();
			return false;
		} catch (IOException e) {
			logger.error(e.getMessage());//e.printStackTrace();
			return false;
		}
		return true;
	}
	
	public static Message receiveSemop(int portaLocal){
		Message message = new Message();
		logger.setLevel(level);
		try {			
			ServerSocket receiveServerSocket = new ServerSocket(portaLocal);
			Socket receiveClientSocket = receiveServerSocket.accept();
			DataInputStream in = new DataInputStream(receiveClientSocket.getInputStream());
			message.setPorta(in.readInt());
			message.setMsg(in.readInt());
			message.setTimeStamp(in.readInt());
			in.close();
			receiveClientSocket.close();
			receiveServerSocket.close();
			return message;
		} catch (IOException e) {
			logger.error(e.getMessage());//			e.printStackTrace();
			return null;
		}		
	}
	
	public static void broadCastSemop(ArrayList<Integer> destinos, Message msg){
		for(int i=0; i < destinos.size(); i++){
			while(!sendSemop(destinos.get(i),msg)){
				; //operation is already done in while lace
			}
		}		
	}
	
	public static boolean sendGo(int portaDestino,int timeStamp){
		logger.setLevel(level);
		try {
			Socket sendSocket = new Socket("localhost",portaDestino);
			DataOutputStream out = new DataOutputStream(sendSocket.getOutputStream());
			out.writeInt(timeStamp);
			out.close();
			sendSocket.close();
			return true;
		} catch (UnknownHostException e) {
			logger.error(e.getMessage());//			e.printStackTrace();
			return false;
		} catch (IOException e) {
			logger.error(e.getMessage());//			e.printStackTrace();
			return false;
		}	
		
	}
	
	public static int receiveGo(int portaLocal){
		logger.setLevel(level);
		try {
			int logicalClock = 0;
			ServerSocket receiveServerSocket = new ServerSocket(portaLocal);
			Socket receiveClientSocket = receiveServerSocket.accept();
			DataInputStream in = new DataInputStream(receiveClientSocket.getInputStream());
			logicalClock = in.readInt(); //do nothing
			in.close();
			receiveClientSocket.close();
			receiveServerSocket.close();
			return logicalClock;
		} catch (IOException e) {
			logger.error(e.getMessage());//			e.printStackTrace();
			return 0;
		}
		
	}
	
	
	

}
